package com.guiji.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.guiji.entity.*;
import com.guiji.exception.GlobalException;
import io.restassured.RestAssured;
import io.restassured.config.LogConfig;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.core.util.JsonUtils;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description:
 * @author: Jodie
 * @time: 2022/11/15
 */
@Slf4j
public class HttpUtils {

    /**
     * 请求类型:FORM表单
     */
    private static final String REQUEST_TYPE_FORM = "application/x-www-form-urlencoded";
    /**
     * 请求类型:JSON体
     */
    private static final String REQUEST_TYPE_JSON = "application/json";

    public static boolean openProxy = false;

    static Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("http", PlainConnectionSocketFactory.INSTANCE)
            .register("https", SslUtil.trustAllHttpsCertificates()).build();

    static PoolingHttpClientConnectionManager connectionManager =
            new PoolingHttpClientConnectionManager(socketFactoryRegistry);


    private static CloseableHttpClient getHttpClient() {
        if (openProxy) {
            HttpHost proxy = new HttpHost("127.0.0.1", 8888, "http");
            RequestConfig defaultRequestConfig = RequestConfig.custom()
                    .setProxy(proxy)
                    .build();
            return HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).setConnectionManager(connectionManager).build();
        }
        return HttpClients.custom().setConnectionManager(connectionManager).build();
    }

    public static HttpResult sendRequest(TestCase testCase){
        return sendRequest(testCase.getType(), testCase.getUrl(), JSON.parseObject(testCase.getHeaders()), JSON.parseObject(testCase.getParams()) );
    }

    public static HttpResult sendRequest(TestResult testResult){
        return sendRequest(testResult.getType(), testResult.getUrl(), JSON.parseObject(testResult.getHeaders()), JSON.parseObject(testResult.getParams()) );
    }

    public static void main(String[] args) {
        String filePath = "src/main/resources/TestAccounts.xlsx";
        List<Account> accounts = ExcelUtils.readAllData(filePath, 1, Account.class);

        String url = "https://apiuat.aia.com.my/digital/security/v2/jwt/accesstoken";
//        String webUrl = "https://www.banca.aia-uat.com.my/Authenticate/";
        Map<String,Object> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put("x-gateway-apikey", "912d967a-2ecc-42ae-a538-bc3273a37bdb");
        headers.put("x-aia-channel-id", "SOAR");
        Map<String, Object> params = new HashMap<>();
        params.put("applicationID", "22a0b2c2-3199-4492-a3f3-a5ae85ef9416");
        params.put("password", "Aia@202109");
        List<Account > failList=new ArrayList<>();
        for (Account account : accounts) {
            params.put("userID", account.getUserID());
//            params.put("username", account.getUserID());
            HttpResult res = sendRequest("post", url, headers, params);
            try {
                if (!(res.getMsg().contains("success"))){
                    failList.add(account);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (!failList.isEmpty()) {
            ExcelUtils.writerListToExcel(failList, "test", "src/main/resources/web750Fail.xlsx", Account.class);
        }
    }

    public static HttpResult sendRequest(String method, String url, Map<String, Object> headers, Map<String, Object> params) {
        CloseableHttpClient httpClient = getHttpClient();
        HttpRequestBase httpRequest;
        HttpResult httpResult = new HttpResult();
        HttpEntity entity = null;
        try {
            switch (method) {
                case "get":
                    httpRequest = new HttpGet(url);
                    break;
                case "post":
                    httpRequest = new HttpPost(url);
                    choosePostPattern(headers, params, (HttpPost) httpRequest);
                    break;
                case "put":
                    httpRequest = new HttpPut(url);
                    StringEntity str = new StringEntity(JSON.toJSONString(params), StandardCharsets.UTF_8);
                    ((HttpPut)httpRequest).setEntity(str);
                    break;
                default:
                    httpRequest = new HttpDelete(url);
                    break;
            }
            if (MapUtils.isNotEmpty(headers)) {
                for (String key : headers.keySet()) {
                    httpRequest.addHeader(key, String.valueOf(headers.get(key)));
                }
            }
            log.info("url:{}", url);
            log.info("reqParams:{}", params);
            log.info("reqHeader:{}",headers);
            CloseableHttpResponse httpResponse = httpClient.execute(httpRequest);
            int statusCode = httpResponse.getStatusLine().getStatusCode();
            entity = httpResponse.getEntity();
            String resBody = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            httpResult.setMsg(resBody);
            httpResult.setHeaders(httpResponse.getAllHeaders());
            httpResult.setCode(statusCode);
            log.info("response:{}", resBody);
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            close(entity);
        }
        return httpResult;
    }

    private static void choosePostPattern(Map<String, Object> headers, Map<String, Object> params, HttpPost httpRequest) {
        String header = JSONObject.toJSONString(headers);
        if (header.contains(REQUEST_TYPE_FORM)) {
            ArrayList<BasicNameValuePair> parameters = new ArrayList<>();
            params.forEach((k, v) -> parameters.add(new BasicNameValuePair(k, String.valueOf(v))));
            try {
                httpRequest.setEntity(new UrlEncodedFormEntity(parameters, StandardCharsets.UTF_8));
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if (header.contains(REQUEST_TYPE_JSON)) {
            StringEntity str = new StringEntity(JSON.toJSONString(params), StandardCharsets.UTF_8);
            httpRequest.setEntity(str);
        } else {
            throw new GlobalException("not support this post type");
        }
    }

    private static void close(HttpEntity entity) {
        try {
            EntityUtils.consume(entity);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过RestAssured发送http请求
     *
     * @param testCase Excel中的case
     * @return  返回响应结果
     */
    public static Response sendRequestByRest(TestCase testCase) {
        long start = System.currentTimeMillis();
        Response response;
        String requestParams = testCase.getParams();
        Map<String, Object> map = JSON.parseObject(testCase.getHeaders());
        String url = testCase.getUrl();
        String method = testCase.getType();
        RequestSpecification requestSpecification = RestAssured.given().log().all().headers(map);
        switch (method){
            case "get":
                if (requestParams != null) {
                    response = requestSpecification.queryParam(requestParams).when().get(url);
                } else {
                    response = requestSpecification.when().get(url);
                }
                break;
            case "post":
                response = requestSpecification.body(requestParams).when().post(url);
                break;
            case "put":
                response = requestSpecification.body(requestParams).when().put(url);
                break;
            default:
                response = requestSpecification.body(requestParams).when().delete(url);
                break;
        }
        response.then().log().all().extract().response();
        long end = System.currentTimeMillis();
        System.out.println("spend:"+(end-start));

        return response;
    }

}
